package org.jetnuke.modules.blog.utils;

import org.apache.log4j.Logger;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.sql.Connection;
import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.jforum.DBConnection;
import net.jforum.JForumExecutionContext;
import net.jforum.entities.Theme;
import net.jforum.entities.User;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.xmlrpc.XmlRpcClient;
import org.jetnuke.common.BlockInfo;
import org.jetnuke.common.IBlockInfo;
import org.jetnuke.dao.BlogCategoryDAO;
import org.jetnuke.dao.BlogHitsDAO;
import org.jetnuke.dao.BlogPostDAO;
import org.jetnuke.dao.BlogUserSettingsDAO;
import org.jetnuke.dao.DataAccessDriver;
import org.jetnuke.dao.PictureUserSettingsDAO;
import org.jetnuke.entities.BlogCategory;
import org.jetnuke.entities.BlogPost;
import org.jetnuke.entities.BlogUserSettings;
import org.jetnuke.entities.PictureUserSettings;
import org.jetnuke.servlets.Do;

public class BlogUtils {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(BlogUtils.class);

	private BlogUtils() {
	}

	public static boolean isBlogInitialized(int uid) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("isBlogInitialized(int) - start"); //$NON-NLS-1$
		}

		BlogUserSettingsDAO busm = DataAccessDriver.getInst()
				.newBlogUserSettingsDAO();
		BlogUserSettings bus = busm.retrieveByPk(uid);
		if (bus.getID() == 0)
			return false;

		if (logger.isDebugEnabled()) {
			logger.debug("isBlogInitialized(int) - end"); //$NON-NLS-1$
		}
		return true;
	}

	public static void initializeBlog(int uid) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("initializeBlog(int) - start"); //$NON-NLS-1$
		}

		BlogCategoryDAO bcm = DataAccessDriver.getInst().newBlogCategoryDAO();
		List ls = bcm.selectByUser(uid);
		if (ls.isEmpty()) {
			BlogCategory bc = new BlogCategory();
			bc.setAID(uid);
			bc.setNAME("Uncategorized");
			bc.setDESCRIPTION("Uncategorized Category");
			bc.setPARENTID(-1);
			bcm.addNew(bc);
		}
		BlogUserSettingsDAO busm = DataAccessDriver.getInst()
				.newBlogUserSettingsDAO();
		BlogUserSettings bus = busm.retrieveByPk(uid);
		if (bus.getID() == 0) {
			bus.setID(uid);
			User user = DataAccessDriver.getInst().newUserDAO().selectById(uid);
			bus.setTITLE(user.getUsername() + "'s Blog");
			bus.setDESCRIPTION("");
			bus.setMAXNUMBERPOST(10);
			int theme = user.getThemeId();
			if (theme == 0)
				theme = 1;
			bus.setSTYLE(theme);
			busm.insert(bus);

		}

		if (logger.isDebugEnabled()) {
			logger.debug("initializeBlog(int) - end"); //$NON-NLS-1$
		}
	}

	public static void manageStyle(BlogUserSettings bus, VelocityContext vc,
			List preLeftBlocks) {
		if (logger.isDebugEnabled()) {
			logger
					.debug("manageStyle(BlogUserSettings, VelocityContext, List) - start"); //$NON-NLS-1$
		}

		String _styleFolder = "_styleFolder";
		String currentStyle = null;
		try {
			Theme tm = net.jforum.dao.DataAccessDriver.getInstance()
					.newThemeDAO().selectByID(bus.getSTYLE());
			currentStyle = tm.getStyleName();
		} catch (Throwable e) {
			logger
					.warn(
							"manageStyle(BlogUserSettings, VelocityContext, List) - exception ignored", e); //$NON-NLS-1$

		}
		if (currentStyle != null)
			vc.put(_styleFolder, "style/" + currentStyle);
		vc.put("_currentStyle", currentStyle);
		vc.put("_preBlocks", preLeftBlocks);
		if (bus.getBLOCKTITLE1() != null && bus.getBLOCKTITLE1().length() > 0
				&& bus.getBLOCKCONTENT1() != null
				&& bus.getBLOCKCONTENT1().length() > 0) {
			preLeftBlocks.add(createBlockInfo(bus.getBLOCKTITLE1(), bus
					.getBLOCKCONTENT1()));
		}
		if (bus.getBLOCKTITLE2() != null && bus.getBLOCKTITLE2().length() > 0
				&& bus.getBLOCKCONTENT2() != null
				&& bus.getBLOCKCONTENT2().length() > 0) {
			preLeftBlocks.add(createBlockInfo(bus.getBLOCKTITLE2(), bus
					.getBLOCKCONTENT2()));
		}
		if (bus.getBLOCKTITLE3() != null && bus.getBLOCKTITLE3().length() > 0
				&& bus.getBLOCKCONTENT3() != null
				&& bus.getBLOCKCONTENT3().length() > 0) {
			preLeftBlocks.add(createBlockInfo(bus.getBLOCKTITLE3(), bus
					.getBLOCKCONTENT3()));
		}
		if (bus.getBLOCKTITLE4() != null && bus.getBLOCKTITLE4().length() > 0
				&& bus.getBLOCKCONTENT4() != null
				&& bus.getBLOCKCONTENT4().length() > 0) {
			preLeftBlocks.add(createBlockInfo(bus.getBLOCKTITLE4(), bus
					.getBLOCKCONTENT4()));
		}
		if (bus.getBLOCKTITLE5() != null && bus.getBLOCKTITLE5().length() > 0
				&& bus.getBLOCKCONTENT5() != null
				&& bus.getBLOCKCONTENT5().length() > 0) {
			preLeftBlocks.add(createBlockInfo(bus.getBLOCKTITLE5(), bus
					.getBLOCKCONTENT5()));
		}

		if (logger.isDebugEnabled()) {
			logger
					.debug("manageStyle(BlogUserSettings, VelocityContext, List) - end"); //$NON-NLS-1$
		}
	}

	private static IBlockInfo createBlockInfo(String title, String content) {
		if (logger.isDebugEnabled()) {
			logger.debug("createBlockInfo(String, String) - start"); //$NON-NLS-1$
		}

		BlockInfo bInfo = new BlockInfo();

		bInfo.setPath("");
		bInfo.setTitle(title);
		bInfo.setAdminOnly(false);
		bInfo.setAnonymousOnly(false);
		bInfo.setBlockClass("org.jetnuke.common.BasicBlock");
		bInfo.setContent(content);
		bInfo.setPosition("l");
		bInfo.setValid(true);
		bInfo.setActivated(true);

		if (logger.isDebugEnabled()) {
			logger.debug("createBlockInfo(String, String) - end"); //$NON-NLS-1$
		}
		return bInfo;
	}

	public static IBlockInfo createUserBlockInfo(VelocityContext vc, User us) {
		if (logger.isDebugEnabled()) {
			logger.debug("createUserBlockInfo(VelocityContext, User) - start"); //$NON-NLS-1$
		}

		StringWriter sw = new StringWriter();
		try {
			PictureUserSettingsDAO pusm = DataAccessDriver.getInst()
					.newPictureUserSettingsDAO();
			PictureUserSettings bus = pusm.retrieveByPk(us.getId());
			if (bus.getID() != 0) {
				vc.put("hasPicture", Boolean.TRUE);
			}

			Template t = Velocity.getTemplate("/modules/blog/user_block.vm");
			vc.put("user", us);
			BlogCategoryDAO bcm = DataAccessDriver.getInst()
					.newBlogCategoryDAO();
			List ls = bcm.selectByUser(us.getId());
			vc.put("blogCategories", ls);
			t.merge(vc, sw);
		} catch (Exception e) {
			logger
					.warn(
							"createUserBlockInfo(VelocityContext, User) - exception ignored", e); //$NON-NLS-1$

		}
		String title = (String) vc.get("_THIS_BLOG");
		IBlockInfo bInfo = createBlockInfo(title, sw.toString());

		if (logger.isDebugEnabled()) {
			logger.debug("createUserBlockInfo(VelocityContext, User) - end"); //$NON-NLS-1$
		}
		return bInfo;
	}

	public static boolean trackBack(String trackbackURL,
			String urlEncodedTitle, String urlEncodedExcerpt, String permalink,
			String urlEncodedBlogName) {
		if (logger.isDebugEnabled()) {
			logger
					.debug("trackBack(String, String, String, String, String) - start"); //$NON-NLS-1$
		}

		String queryString = "title=" + urlEncodedTitle + "&url=" + permalink
				+ "&blog_name=" + urlEncodedBlogName + "&excerpt="
				+ urlEncodedExcerpt;

		PostMethod post = new PostMethod(trackbackURL);

		HttpClient client = new HttpClient();
		try {
			client.setConnectionTimeout(8000);
			String host = post.getURI().getHost();
			post.setRequestHeader("Host", host);
			post.setRequestHeader("Content-type",
					"application/x-www-form-urlencoded; charset=UTF-8");
			post
					.setRequestHeader("User-Agent", "JetNuke/");
			post.setRequestHeader("Content-Length", String.valueOf(queryString
					.length()));
			post.setRequestBody(queryString);

			int returnValue = client.executeMethod(post);
			if (returnValue != 200) {

				if (logger.isDebugEnabled()) {
					logger
							.debug("trackBack(String, String, String, String, String) - end"); //$NON-NLS-1$
				}
				return false;
			}
			BufferedInputStream bis = new BufferedInputStream(post
					.getResponseBodyAsStream());
			byte[] buff = new byte[2048];
			int bytesRead;
			ByteArrayOutputStream baos = new ByteArrayOutputStream(2048 * 20);
			// Simple read/write loop.
			while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
				baos.write(buff, 0, bytesRead);
			}
			String response = baos.toString();

			/*
			 * From http://www.sixapart.com/pronet/docs/trackback_spec: In the
			 * event of a succesful ping, the server MUST return a response in
			 * the following format:
			 * 
			 * <?xml version="1.0" encoding="utf-8"?> <response> <error>0</error>
			 * </response>
			 * 
			 * 
			 */

			if (response.indexOf("<error>0</error>") > -1) {
				if (logger.isDebugEnabled()) {
					logger
							.debug("trackBack(String, String, String, String, String) - end"); //$NON-NLS-1$
				}
				return true;
			}

		} catch (Exception e) {
			logger
					.warn(
							"trackBack(String, String, String, String, String) - exception ignored", e); //$NON-NLS-1$
		} finally {
			post.releaseConnection();
		}

		if (logger.isDebugEnabled()) {
			logger
					.debug("trackBack(String, String, String, String, String) - end"); //$NON-NLS-1$
		}
		return false;
	}

	public static void doTrackback(String nukeURL, int postID) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("doTrackback(String, int) - start"); //$NON-NLS-1$
		}

		Connection conn = null;
		if (SystemGlobals.getBoolValue(ConfigKeys.BACKGROUND_TASKS)) {
			conn = DBConnection.getImplementation().getConnection();
			JForumExecutionContext ex = new JForumExecutionContext();
			ex.setConnection(conn);
			JForumExecutionContext.set(ex);
			// DataHolder dHolder=new DataHolder();
			// dHolder.setConnection(conn);
			// JForum.setThreadLocalData(dHolder);
		}
		try {
			BlogPostDAO bpm = DataAccessDriver.getInst().newBlogPostDAO();
			BlogPost bp = bpm.retrieveByPK(postID);
			String toPing = bp.getTOPING();
			String[] pings = toPing.split(" ");
			TreeSet pingsSet = new TreeSet(Arrays.asList(pings));
			String[] pungs = bp.getPINGED().split(" ");
			TreeSet pungsSet = new TreeSet(Arrays.asList(pungs));

			BlogUserSettingsDAO busm = DataAccessDriver.getInst()
					.newBlogUserSettingsDAO();
			BlogUserSettings bus = busm.retrieveByPk(bp.getAID());

			String urlEncodedTitle = URLEncoder.encode(bp.getPOSTTITLE(),
					"UTF-8");

			String urlEncodedExcerpt = URLEncoder.encode(bp.getSHORTTEXT(),
					"UTF-8");
			String permalink = nukeURL + "do/blog/show_page?id=" + postID;
			String urlEncodedBlogName = URLEncoder.encode(bus.getTITLE(),
					"UTF-8");
			Iterator it = pingsSet.iterator();
			while (it.hasNext()) {
				String ping = ((String) it.next()).trim();
				if (!pungsSet.contains(ping)) {
					boolean tracked = trackBack(ping, urlEncodedTitle,
							urlEncodedExcerpt, permalink, urlEncodedBlogName);
					if (tracked) {
						pungsSet.add(ping);
						it.remove();

					}
				}
			}
			String[] newPungs = (String[]) pungsSet.toArray(new String[pungsSet
					.size()]);
			String[] newPings = (String[]) pingsSet.toArray(new String[pingsSet
					.size()]);
			StringBuffer sbPing = new StringBuffer("");
			for (int i = 0; i < newPings.length; i++) {
				sbPing.append(newPings[i].trim());
				if (i < newPings.length - 1)
					sbPing.append(" ");
			}

			StringBuffer sbPung = new StringBuffer("");
			for (int i = 0; i < newPungs.length; i++) {
				sbPung.append(newPungs[i].trim());
				if (newPungs[i].trim().length() > 0 && i < newPungs.length - 1)
					sbPung.append(" ");
			}
			bp.setPINGED(sbPung.toString());
			bp.setTOPING(sbPing.toString());
			bpm.update(bp);
		} finally {
			if (SystemGlobals.getBoolValue(ConfigKeys.BACKGROUND_TASKS)) {
				if (conn != null) {
					try {
						DBConnection.getImplementation()
								.releaseConnection(conn);
					} catch (Exception e) {
						logger
								.warn(
										"doTrackback(String, int) - exception ignored", e); //$NON-NLS-1$
					}
				}
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("doTrackback(String, int) - end"); //$NON-NLS-1$
		}
	}

	private static final String PINGBACK_METHOD = "pingback.ping";
	private static final String X_PINGBACK_HEADER = "X-Pingback";
	private static final String PINGBACK_LINK_REGEX = "<link rel=\"pingback\" href=\"([^\"]+)\" ?/?>";
	private static final String HREF_REGEX = "href\\s*=\\s*\"(.*?)\"";
	private static final Pattern pingbackLinkPattern = Pattern.compile(
			PINGBACK_LINK_REGEX, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
					| Pattern.UNICODE_CASE | Pattern.DOTALL);
	private static final Pattern hrefPattern = Pattern.compile(HREF_REGEX,
			Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.UNICODE_CASE
					| Pattern.DOTALL);

	public static void doPingback(String url, int id) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("doPingback(String, int) - start"); //$NON-NLS-1$
		}

		String permalink = url + "do/blog/show_page?id=" + id;
		Connection conn = null;
		String lineSeparator = System.getProperty("line.separator");

		if (SystemGlobals.getBoolValue(ConfigKeys.BACKGROUND_TASKS)) {
			conn = DBConnection.getImplementation().getConnection();
			JForumExecutionContext ex = JForumExecutionContext.get();
			ex.setConnection(conn);
			JForumExecutionContext.set(ex);
		}
		try {
			BlogPostDAO bpm = DataAccessDriver.getInst().newBlogPostDAO();
			BlogPost bp = bpm.retrieveByPK(id);

			// String toPing=bp.getTOPING();
			// String[]pings=toPing.split(" ");
			// TreeSet pingsSet=new TreeSet(Arrays.asList(pings));
			String[] pungs = bp.getPINGED().split(" ");
			TreeSet pungsSet = new TreeSet(Arrays.asList(pungs));

			String text = bp.getPOSTCONTENT();

			Matcher hrefMatcher = hrefPattern.matcher(text);
			String targetURI = null;
			TreeSet targetURISet = new TreeSet();
			while (hrefMatcher.find()) {
				targetURI = hrefMatcher.group(1);
				targetURISet.add(targetURI);
			}
			Iterator it = targetURISet.iterator();
			while (it.hasNext()) {
				targetURI = (String) it.next();
				if (!targetURI.toLowerCase().startsWith("http"))
					continue;
				if (pungsSet.contains(targetURI))
					continue;
				try {

					HttpClient client = new HttpClient();
					GetMethod gm = new GetMethod(targetURI);

					gm.setRequestHeader("User-Agent", "JetNuke/");
					client.setConnectionTimeout(8000);
					client.executeMethod(gm);
					Header hd = gm.getResponseHeader(X_PINGBACK_HEADER);
					String pingbackURL = null;
					if (hd != null)
						pingbackURL = hd.getValue();
					if (pingbackURL == null) {

						BufferedReader bufferedReader = new BufferedReader(
								new InputStreamReader(gm
										.getResponseBodyAsStream(), "UTF-8"));
						StringBuffer content = new StringBuffer();
						String input;
						while ((input = bufferedReader.readLine()) != null) {
							content.append(input).append(lineSeparator);
						}
						bufferedReader.close();

						Matcher pingbackLinkMatcher = pingbackLinkPattern
								.matcher(content.toString());
						if (pingbackLinkMatcher.find()) {
							pingbackURL = pingbackLinkMatcher.group(1);
						}
					}
					if (pingbackURL != null && targetURI != null) {
						Vector parameters = new Vector();
						parameters.add(permalink);
						parameters.add(targetURI);
						XmlRpcClient xmlRpcClient = new XmlRpcClient(
								pingbackURL);

						xmlRpcClient.execute(PINGBACK_METHOD, parameters);
						pungsSet.add(targetURI);
						// executeAsync should be better. But it doesn't work on
						// xml-rpc 2.0!!!
						// It throws a NPE
						// See
						// http://www.opensubscriber.com/message/xmlrpc-dev@ws.apache.org/1865013.html
						// System.out.println(obj);

						// xmlRpcClient.executeAsync(PINGBACK_METHOD,parameters,new
						// AsyncCallback(){
						//
						// public void handleResult(Object arg0, URL arg1,
						// String arg2) {
						// System.out.println("ok:"+arg0+" "+arg1.toString()+"
						// "+arg2);
						//								
						// }
						//
						// public void handleError(Exception arg0, URL arg1,
						// String arg2) {
						// System.out.println("error:"+arg0+"
						// "+arg1.toString()+" "+arg2);
						//								
						// }});
					}

				} catch (Throwable t) {
					logger.warn(
							"doPingback(String, int) - exception ignored", t); //$NON-NLS-1$
				}
			}
			String[] newPungs = (String[]) pungsSet.toArray(new String[pungsSet
					.size()]);
			StringBuffer sbPung = new StringBuffer("");
			for (int i = 0; i < newPungs.length; i++) {
				sbPung.append(newPungs[i]);
				if (newPungs[i].trim().length() > 0 && i < newPungs.length - 1)
					sbPung.append(" ");
			}
			bp.setPINGED(sbPung.toString());
			bpm.update(bp);
		} finally {
			if (SystemGlobals.getBoolValue(ConfigKeys.BACKGROUND_TASKS)) {
				if (conn != null) {
					try {
						DBConnection.getImplementation()
								.releaseConnection(conn);
					} catch (Exception e) {
						logger
								.warn(
										"doPingback(String, int) - exception ignored", e); //$NON-NLS-1$
					}
				}
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("doPingback(String, int) - end"); //$NON-NLS-1$
		}
	}

	public static IBlockInfo createStatInfo(VelocityContext vc) {
		if (logger.isDebugEnabled()) {
			logger.debug("createStatInfo(VelocityContext) - start"); //$NON-NLS-1$
		}

		StringWriter sw = new StringWriter();
		try {
			Template t = Velocity.getTemplate("/modules/blog/blog_stat.vm");
			BlogHitsDAO bhm = DataAccessDriver.getInst().newBlogHitsDAO();
			List ls = bhm.selectHotWeeks();
			Iterator it = ls.iterator();
			HashMap mp = new HashMap();
			while (it.hasNext()) {
				List intList = (List) it.next();
				// int count=((Integer)intList.get(0)).intValue();
				int author = ((Integer) intList.get(1)).intValue();
				BlogUserSettings bus = DataAccessDriver.getInst()
						.newBlogUserSettingsDAO().retrieveByPk(author);
				mp.put(new Integer(author), bus);
			}
			vc.put("mp1", mp);
			vc.put("ls1", ls);
			t.merge(vc, sw);
		} catch (Exception e) {
			logger.warn(
					"createStatInfo(VelocityContext) - exception ignored", e); //$NON-NLS-1$
		}
		String title = (String) vc.get("_HOT_USER_BLOGS");
		IBlockInfo bInfo = createBlockInfo(title, sw.toString());

		if (logger.isDebugEnabled()) {
			logger.debug("createStatInfo(VelocityContext) - end"); //$NON-NLS-1$
		}
		return bInfo;
	}

	public static IBlockInfo createCalendarBlock(VelocityContext vc,
			GregorianCalendar gc, int uid) {
		if (logger.isDebugEnabled()) {
			logger
					.debug("createCalendarBlock(VelocityContext, GregorianCalendar, int) - start"); //$NON-NLS-1$
		}

		int year = 0;
		int month = 0;

		StringWriter sw = new StringWriter();
		try {

			year = gc.get(java.util.Calendar.YEAR);
			month = gc.get(java.util.Calendar.MONTH) + 1;// because java
															// months start from
															// 0

			Set postDaysSet = DataAccessDriver.getInst().newBlogPostDAO()
					.getPostDays(uid, month, year);
			vc.put("postSet", postDaysSet);
			HashMap days = new HashMap();
			// int subtract=getFirstDayOfWeek();
			Locale locale = (Locale) vc.get("_locale");
			String[] DAYS = new DateFormatSymbols(locale).getShortWeekdays();
			String[] MONTHS = new DateFormatSymbols(locale).getMonths();
			String[] dstArray = new String[7];
			System.arraycopy(DAYS, 1, dstArray, 0, 7);

			vc.put("current_month", new Integer(month - 1));
			vc.put("DAYS", dstArray);
			gc = getFirstDayOnCalendar(year, month - 1);
			GregorianCalendar dt = gc;
			for (int i = 0; i < 6; i++) {
				for (int j = 0; j < 7; j++) {
					GregorianCalendar tmp = new GregorianCalendar();
					tmp.setTime(dt.getTime());
					days.put(new Integer(i + j * 7), tmp);
					dt.add(java.util.Calendar.DATE, 1);
				}
			}
			vc.put("days", days);// Arrays of GregorianCalendar!
			int nextYear = year;
			int previousYear = year;
			int nextMonth = month + 1;
			if (nextMonth > 12) {
				nextMonth = 1;
				nextYear += 1;
			}
			int previousMonth = month - 1;
			if (previousMonth < 1) {
				previousYear -= 1;
				previousMonth = 12;
			}
			vc.put("previousMonth", new Integer(previousMonth));
			vc.put("nextMonth", new Integer(nextMonth));
			vc.put("previousYear", new Integer(previousYear));
			vc.put("nextYear", new Integer(nextYear));
			vc.put("currentMonthDes", MONTHS[month - 1]);
			vc.put("year", new Integer(year));

			vc.put("calendar_aid", new Integer(uid));
			Template t = Velocity.getTemplate("/modules/blog/calendar.vm");
			t.merge(vc, sw);
		} catch (Exception e) {
			logger
					.warn(
							"createCalendarBlock(VelocityContext, GregorianCalendar, int) - exception ignored", e); //$NON-NLS-1$
		}
		String title = (String) vc.get("_CALENDAR");
		IBlockInfo bInfo = createBlockInfo(title, sw.toString());

		if (logger.isDebugEnabled()) {
			logger
					.debug("createCalendarBlock(VelocityContext, GregorianCalendar, int) - end"); //$NON-NLS-1$
		}
		return bInfo;
	}

	private static GregorianCalendar getFirstDayOnCalendar(int year_, int month_) {
		if (logger.isDebugEnabled()) {
			logger.debug("getFirstDayOnCalendar(int, int) - start"); //$NON-NLS-1$
		}

		GregorianCalendar g = new GregorianCalendar(year_, month_, 1);
		int dow = g.get(java.util.Calendar.DAY_OF_WEEK);

		if (dow != 1)
			g.add(java.util.Calendar.DATE, ((dow - 1) * -1));

		if (logger.isDebugEnabled()) {
			logger.debug("getFirstDayOnCalendar(int, int) - end"); //$NON-NLS-1$
		}
		return g;
	}
}
